﻿using Autofac;
using Autofac.Extensions.DependencyInjection;
using Autofac.Extras.DynamicProxy;
using Castle.DynamicProxy;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Module = Autofac.Module;

namespace Dotnet.Utils.Utility.Dependency
{
    public static class AutofacUtil
    {
        public static void Init()
        {
            //builder.Host.AddAutofac();
            //让控制器实例由容器创建(一定要加)
            //builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
            //...

            //注入_container单例
            //app.Services.InitContainer();

            //通过特性标签注入实体类可以使用Autofac.Annotation：https://github.com/yuzd/Autofac.Annotation
        }

        public static IHostBuilder AddAutofac(this IHostBuilder host)
        {
            //Autofac替换内置DI
            host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
            host.ConfigureContainer<ContainerBuilder>(containerBuilder => containerBuilder.RegisterModule(new AutofacRegisterModule()));
            return host;

            //注入方式,默认瞬时
            //一般使用瞬时和单例即可

            //瞬时
            //containerBuilder.RegisterType<UserService>().As<IUserService>().InstancePerDependency().PropertiesAutowired();

            //单例：
            //containerBuilder.RegisterType<UserService>().As<IUserService>().SingleInstance().PropertiesAutowired();

            //每个生命周期范围一个实例
            //containerBuilder.RegisterType<UserService>().As<IUserService>().InstancePerLifetimeScope().PropertiesAutowired();

            //Web请求范围一个实例
            //containerBuilder.RegisterType<UserService>().As<IUserService>().InstancePerRequest().PropertiesAutowired();
        }
    }

    /// <summary>
    /// Ioc管理
    /// </summary>
    public static class IocManager
    {
        private static object obj = new object();
        private static ILifetimeScope _container { get; set; }

        public static void InitContainer(this IServiceProvider serviceProvider)
        {
            if (_container == null)
            {
                lock (obj)
                {
                    if (_container == null)
                    {
                        _container = serviceProvider.GetAutofacRoot();
                    }
                }
            }
        }

        /// <summary>
        /// 获取实例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T GetService<T>() where T : notnull
        {
            return _container.Resolve<T>();
        }

        /// <summary>
        /// 获取实例
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static object GetService(Type type)
        {
            return _container.Resolve(type);
        }

        /// <summary>
        /// 获取实例(一对多)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T GetService<T>(Type type) where T : notnull
        {
            return GetServices<T>().FirstOrDefault(a => a.GetType().Equals(type)) ?? _container.Resolve<T>();
        }

        /// <summary>
        /// 获取实例列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static IEnumerable<T> GetServices<T>() where T : notnull
        {
            return _container.Resolve<IEnumerable<T>>();
        }

        /// <summary>
        /// 判断是否注入
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static bool IsRegistered<T>()
        {
            return _container.IsRegistered<T>();
        }

        /// <summary>
        /// 判断是否注入
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static bool IsRegistered(Type serviceType)
        {
            return _container.IsRegistered(serviceType);
        }
    }

    public class AutofacRegisterModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            //批量自动注入,把需要注入层的程序集传参数
            BatchRegister(builder, typeof(AutofacRegisterModule).Assembly);

            //注入LazyService
            //builder.RegisterType<LazyService>().InstancePerDependency().PropertiesAutowired();

            //注入AOP
            //builder.RegisterType<AutofacAOP>();

            //让控制器实例由容器创建,不加就不支持属性注入,或者可以使用BaseController继承ControllerBase, ITransitDenpendency
            //var controllerBaseType = typeof(ControllerBase);
            //builder.RegisterAssemblyTypes(typeof(Program).Assembly)
            //    .Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType).PropertiesAutowired();

            //程序集注入
            //builder.RegisterAssemblyTypes(assembly).AsSelf().AsImplementedInterfaces().InstancePerDependency().PropertiesAutowired();

            //绑定事件
            //在对象生命周期的不同阶段使用事件。Autofac暴露五个事件接口供实例的按如下顺序调用
            //1)OnRegistered
            //2)OnPreparing
            //3)OnActivated
            //4)OnActivating
            //5)OnRelease
            //builder.RegisterAssemblyTypes(assembly).OnRegistered(e => Console.WriteLine("在注册的时候调用!")).OnPreparing(e => Console.WriteLine("在准备创建的时候调用!")).OnActivating(e => Console.WriteLine("在创建之前调用!")).OnActivated(e => Console.WriteLine("创建之后调用!")).OnRelease(e => Console.WriteLine("在释放占用的资源之前调用!"));

            //实体类赋默认值
            //var person = new User { Age = 100 };
            //builder.RegisterInstance(person).As<User>();
            //builder.RegisterInstance(person).As(typeof(User));
            //builder.RegisterType<User>().WithProperty("Age", 1000).InstancePerDependency().PropertiesAutowired();
            //builder.RegisterType<User>().InstancePerDependency().PropertiesAutowired()
            //.OnActivated(e =>
            //{
            //    var instance = e.Instance;
            //    instance.Age = 100;
            //});

            //初始化执行
            //builder.RegisterType<GlobalInitializer>().As<IStartable>().SingleInstance();
        }

        /// <summary>
        /// 批量注入扩展
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="assembly"></param>
        private void BatchRegister(ContainerBuilder builder, Assembly assembly)
        {
            Type transientType = typeof(ITransitDenpendency);
            Type singletonType = typeof(ISingletonDenpendency);
            Type scopeType = typeof(IScopeDenpendency);

            //.EnableInterfaceInterceptors();后面加载此方法使用拦截器
            builder.RegisterAssemblyTypes(assembly).Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Contains(transientType))
                .AsSelf().AsImplementedInterfaces().InstancePerDependency().PropertiesAutowired();

            builder.RegisterAssemblyTypes(assembly).Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Contains(singletonType))
               .AsSelf().AsImplementedInterfaces().SingleInstance().PropertiesAutowired();

            builder.RegisterAssemblyTypes(assembly).Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Contains(scopeType))
               .AsSelf().AsImplementedInterfaces().InstancePerLifetimeScope().PropertiesAutowired();

            //批量注入瞬时模式,查找所有类只要没有继承接口或者继承一个接口就注入
            //Type[] types = { transientType, singletonType, scopeType };
            //builder.RegisterAssemblyTypes(assembly).Where(t => t.IsClass && !t.IsAbstract && !types.Contains(t)
            //&& t.GetInterfaces().Length <= 1)
            //    .AsSelf().AsImplementedInterfaces().InstancePerDependency().PropertiesAutowired();
        }
    }

    public class User
    {
        public int Age { get; set; }
    }

    /// <summary>
    /// 瞬时注入
    /// </summary>
    public interface ITransitDenpendency
    { }

    /// <summary>
    /// 单例注入标识
    /// </summary>
    public interface ISingletonDenpendency
    { }

    /// <summary>
    /// 生命周期注入标识
    /// </summary>
    public interface IScopeDenpendency
    { }

    /// <summary>
    /// 拦截器
    /// </summary>
    public class AutofacAOP : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            Console.WriteLine($"拦截器被调用,方法名为{invocation.Method.Name}");
            //执行被拦截的方法
            invocation.Proceed();
            Console.WriteLine($"拦截器调用完成,返回结果为{invocation.ReturnValue}");
        }
    }

    /// <summary>
    /// 拦截器测试类
    /// </summary>
    [Intercept(typeof(AutofacAOP))]
    public class Test
    {
        //必须标记为虚方法才可以触发拦截器
        public virtual void Show()
        {
            Console.WriteLine("执行中");
        }
    }
}